<chapter xml:id="str2num.h">
<title><tt>__vic/str2num.h</tt></title>


<chapter xml:id="decimal_to_number">
<title><tt>decimal_to_number()</tt></title>

<code-block lang="C++"><![CDATA[
#if __cpp_lib_string_view // since C++17

void decimal_to_number(std::string_view s, long long &res);
void decimal_to_number(std::string_view s, long &res);
void decimal_to_number(std::string_view s, int &res);
void decimal_to_number(std::string_view s, short &res);
void decimal_to_number(std::string_view s, signed char &res);

void decimal_to_number(std::string_view s, unsigned long long &res);
void decimal_to_number(std::string_view s, unsigned long &res);
void decimal_to_number(std::string_view s, unsigned &res);
void decimal_to_number(std::string_view s, unsigned short &res);
void decimal_to_number(std::string_view s, unsigned char &res);

template<class Integer>
[[nodiscard]] Integer decimal_to_number(std::string_view s);

#else // until C++17

void decimal_to_number(const std::string &s, long long &res);
void decimal_to_number(const std::string &s, long &res);
void decimal_to_number(const std::string &s, int &res);
void decimal_to_number(const std::string &s, short &res);
void decimal_to_number(const std::string &s, signed char &res);

void decimal_to_number(const std::string &s, unsigned long long &res);
void decimal_to_number(const std::string &s, unsigned long &res);
void decimal_to_number(const std::string &s, unsigned &res);
void decimal_to_number(const std::string &s, unsigned short &res);
void decimal_to_number(const std::string &s, unsigned char &res);

void decimal_to_number(const char *s, long long &res);
void decimal_to_number(const char *s, long &res);
void decimal_to_number(const char *s, int &res);
void decimal_to_number(const char *s, short &res);
void decimal_to_number(const char *s, signed char &res);

void decimal_to_number(const char *s, unsigned long long &res);
void decimal_to_number(const char *s, unsigned long &res);
void decimal_to_number(const char *s, unsigned &res);
void decimal_to_number(const char *s, unsigned short &res);
void decimal_to_number(const char *s, unsigned char &res);

template<class Integer>
[[nodiscard]] Integer decimal_to_number(const std::string &s);

template<class Integer>
[[nodiscard]] Integer decimal_to_number(const char *s);

#endif
]]></code-block>

<p>Набор функций, преобразующих строки, содержащие десятичное представление
целого числа, в один из стандартных целых типов C++. Входная строка может быть
как C-строкой, так и <tt>std::string</tt>.</p>

<p>В отличие от стандартных преобразователей, вроде <tt>std::strtol()</tt>,
производится строгая проверка на формат строки и диапазон значения. В частности,
лидирующие пробелы и символы, не являющиеся цифрами, в конце не допустимы. Для
беззнаковых типов недопустим символ '-', который <tt>std::strtoul()</tt> по
непонятной причине воспринимает как корректный.</p>

<p>В случае ошибок бросаются исключения:</p>
<list style="bulleted">
    <item><tt>std::invalid_argument</tt> – строка не является корректным целым
        десятичным числом;</item>
    <item><tt>std::range_error</tt> – строка является корректным числом, но
        результат не представим в диапазоне запрошенного типа (целочисленное
        переполнение).</item>
</list>

<p>Для данных функций доступны две категории прототипов:</p>
<list style="numbered">
    <item>Значение возвращается через дополнительный выходной параметр и</item>
    <item>Значение возвращается естественным образом, а его тип задаётся
        аргументом шаблона.</item>
</list>

</chapter>


<chapter xml:id="decimal_to_number_range">
<title><tt>decimal_to_number_range()</tt></title>

<code-block lang="C++"><![CDATA[
template<class T, class InputIterator>
void decimal_to_number_range(InputIterator begin, InputIterator end, T &res);

template<class T, class InputIterator>
[[nodiscard]] T decimal_to_number_range(InputIterator begin, InputIterator end);
]]></code-block>

<p>Функции являются полным аналогом функций <tt>decimal_to_number()</tt> за
тем исключением, что на вход принимают диапазон символов вместо строки.</p>

</chapter>


<chapter xml:id="parse_decimal">
<title><tt>parse_decimal()</tt></title>

<code-block lang="C++"><![CDATA[
#if __cpp_lib_string_view // since C++17

template<class T>
[[nodiscard]] number_parse_result<T> parse_decimal(std::string_view s);

#else // until C++17

template<class T>
[[nodiscard]] number_parse_result<T> parse_decimal(const std::string &s);
template<class T>
[[nodiscard]] number_parse_result<T> parse_decimal(const char *s);

#endif

template<class T, class InputIterator>
[[nodiscard]]
number_parse_result<T> parse_decimal(InputIterator begin, InputIterator end);
]]></code-block>

<p>Аналог функций <tt>decimal_to_number()</tt>, но не бросает исключений.
Возвращаемый объект может тестироваться в bool-контексте, что позволяет узнать
об успехе операции. Также данный объект содержит число-результат в случае
успеха, или код ошибки в противном случае. См. <xref to="number_parse_result"/>
для более подробного описания.</p>

<section><title>Пример</title>
<code-block lang="C++"><![CDATA[
if(auto res = __vic::parse_decimal<int>("123"))
{
    int num = res.value();
    // Use num
}
]]></code-block>
</section>

</chapter>


<chapter xml:id="decimal_parser">
<title><tt>decimal_parser</tt></title>

<code-block lang="C++"><![CDATA[
template<class T>
class decimal_parser
{
    using status = number_parse_status; // только для краткости
public:
    template<class InputIterator>
    [[nodiscard]] status parse(InputIterator begin, InputIterator end);
#if __cpp_lib_string_view // since C++17
    [[nodiscard]] status parse(std::string_view str);
#else // until C++17
    [[nodiscard]] status parse(const std::string &str);
    [[nodiscard]] status parse(const char *str);
#endif
    [[nodiscard]] T result() const;
};
]]></code-block>

<p>Аналог функций <tt>decimal_to_number()</tt>, но ни бросает исключений.
Вместо них <tt>parse()</tt> возвращает коды <xref to="number_parse_status"/>.
</p>

<section><title>Коды статусов</title>
<synopsis>
<prototype>number_parse_status::ok</prototype>
<p>Удачно, результат может быть получен вызовом функции <tt>result()</tt>.</p>
</synopsis>
<synopsis>
<prototype>number_parse_status::invalid_number</prototype>
<p>Строка не является корректным десятичным целым.</p>
</synopsis>
<synopsis>
<prototype>number_parse_status::unrepresentable</prototype>
<p>Строка, возможно, корректна, но результат не представим в диапазоне
запрошенного типа (целочисленное переполнение).</p>
</synopsis>
</section>

<section><title>Члены класса</title>

<synopsis>
<prototype>template&lt;class InputIterator>
[[nodiscard]] status parse(InputIterator begin, InputIterator end)</prototype>
<prototype>[[nodiscard]] status parse(std::string_view str) <badge>C++17</badge></prototype>
<prototype>[[nodiscard]] status parse(const std::string &amp;str) <badge>until C++17</badge></prototype>
<prototype>[[nodiscard]] status parse(const char *str) <badge>until C++17</badge></prototype>
<p>Преобразует диапазон символов или строку в число.</p>
<postcondition>Результат преобразования может быть получен вызовом
<tt>result()</tt>, если возвращён <tt>number_parse_status::ok</tt>.
</postcondition>
</synopsis>

<synopsis>
<prototype>[[nodiscard]] T result() const</prototype>
<p>Возвращает результат преобразования последнего вызова <tt>parse()</tt>.</p>
<precondition>Последний вызов <tt>parse()</tt> вернул
<tt>number_parse_status::ok</tt>.</precondition>
</synopsis>

</section>

<section><title>Пример</title>
<code-block lang="C++"><![CDATA[
template<class T>
bool to_number(const std::string &s, T &result) noexcept
{
    __vic::decimal_parser<T> p;
    if(p.parse(s) != __vic::number_parse_status::ok) return false;
    result = p.result();
    returt true; // 'result' содержит результат преобразования
}
]]></code-block>
</section>

</chapter>


<chapter xml:id="number_parse_status">
<title><tt>number_parse_status</tt></title>

<code-block lang="C++"><![CDATA[
enum class number_parse_status : unsigned char
{
    ok,
    invalid_number,
    unrepresentable
};
using number_parse_status_t = number_parse_status; // for C++98
]]></code-block>

<p>Коды статусов результата разбора.</p>

<section><title>Типы</title>

<synopsis>
<prototype>typename number_parse_status_t</prototype>
<p>Используйте данное имя типа, если коду требуется совместимость с режимом
C++98.</p>
</synopsis>

</section>

</chapter>


<chapter xml:id="number_parse_result">
<title><tt>number_parse_result</tt></title>

<code-block lang="C++"><![CDATA[
template<class T>
class number_parse_result
{
public:
    typedef T value_type;

    number_parse_result(number_parse_status_t s);
    explicit number_parse_result(T n);

    number_parse_status_t status() const;
    explicit operator bool() const;
    bool has_value() const;

    T value() const;
};
]]></code-block>

<p><tt>number_parse_status</tt> + результирующее значение в случае успеха.</p>

<section><title>Члены класса</title>

<synopsis>
<prototype>number_parse_result(number_parse_status_t s)</prototype>
<precondition><tt>s != number_parse_status::ok</tt></precondition>
<postcondition><tt>status() == s</tt></postcondition>
</synopsis>

<synopsis>
<prototype>explicit number_parse_result(T n)</prototype>
<postcondition><tt>has_value() &amp;&amp; value() == n</tt></postcondition>
</synopsis>

<synopsis>
<prototype>number_parse_status_t status() const</prototype>
<p>Статус операции разбора числа.</p>
</synopsis>

<synopsis>
<prototype>bool has_value() const</prototype>
<prototype>explicit operator bool() const</prototype>
<p>Возвращает <tt>status() == number_parse_status::ok</tt>.</p>
</synopsis>

<synopsis>
<prototype>T value() const</prototype>
<p>Число-результат.</p>
<precondition><tt>has_value() == true</tt></precondition>
</synopsis>

</section>

</chapter>


</chapter>
